package com.joymart.config;


import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.joymart.user.model.CachedUser;
import com.joymart.user.service.UserCacheManager;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Component
public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private Algorithm jwtAlgorithm;
    private JWTVerifier jwtVerifier;
    @Autowired
    private UserCacheManager userCacheManager;


    @PostConstruct
    public void init(){
        jwtVerifier = JWT.require(jwtAlgorithm)
                .withIssuer("joymart")
                .build();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        String authHeader = request.getHeader("Authorization");
        if ( !StringUtils.hasText(authHeader) || !authHeader.startsWith("Bearer ")) {
            setTokenIssue("no token present", request);
            filterChain.doFilter(request, response);
            return;
        }

        String token = authHeader.replaceFirst("Bearer ", "");
        DecodedJWT decoded = null;
        try {
             decoded = jwtVerifier.verify(token);

        }catch (Exception e){
            setTokenIssue("malformed token", request);
            filterChain.doFilter(request, response);
            return;
        }


        if(decoded.getExpiresAtAsInstant().isBefore(LocalDateTime.now().toInstant(ZoneOffset.ofHours(+8)))){
            setTokenIssue("token expired", request);
            filterChain.doFilter(request, response);
            return;
        }

        String userId = decoded.getSubject();
        String role = "ROLE_"+ decoded.getClaim("ROLE").asString();
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority(role));
        //本项目中只有A端用户应用RestAuthority
        if(role.equals("ROLE_PARTY_A")){
            List<String> restAuthorities = Optional.ofNullable(userCacheManager.get(userId))
                    .map(CachedUser::getUserRestAuthorities)
                    .orElse(new ArrayList<>());
            restAuthorities.forEach(authority -> authorities.add(new SimpleGrantedAuthority(authority)));
        }

        //注意！ 这里的 subject是 userId而非 username
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(userId, "", authorities);

        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        filterChain.doFilter(request, response);

    }

    private void setTokenIssue(String tokenIssue, HttpServletRequest request){
        UsernamePasswordAuthenticationToken unAuthenticated =
                new UsernamePasswordAuthenticationToken("", "" );

        SecurityContextHolder.getContext().setAuthentication(unAuthenticated);
        request.setAttribute("TOKEN_ISSUE", tokenIssue);
    }
}
